#include <cstdlib>

#include "Commands.hpp"
#include "Utils.hpp"

namespace FeedHandler
{
	namespace detail
	{
		const uint32 cOrderCmdParametersCount = 5;
		const uint32 cTradeCmdParametersCount = 3;
	}

    Command::Ptr CommandFactory::create(const std::string & command)
    {
        if (command.empty())
        {
			throw std::exception("bad command - zero length");
        }
        
        char cmd = command[0];

        Command::Ptr pCmd;
        if (cmd == 'A')
        {
            pCmd.reset(new CmdAddOrder());
        }
        else if (cmd == 'X')
        {
            pCmd.reset(new CmdRemoveOrder());
        }
        else if (cmd == 'M')
        {
            pCmd.reset(new CmdModifyOrder());
        }
		else if (cmd == 'T')
		{
			pCmd.reset(new CmdTrade());
		}
        else
        {
			throw std::exception("unknown command");
        }
        
        pCmd->parse(command);

		return pCmd;
    }

	void OrderCommand::parse(const std::string & command)
	{
		typedef std::list<std::string> StringsList;

		StringsList sList = tokenize(command, ',');

		// assume that all commands have the same structure (cmd,id,side,amount,price)
		if (sList.size() != detail::cOrderCmdParametersCount)
		{
			throw std::exception("bad command");
		}

		StringsList::iterator i = sList.begin(), iEnd = sList.end();

		++i; m_order.id = ::atoi(i->c_str());

		++i; m_order.side = static_cast<Order::Side>(i->c_str()[0]);
		if (m_order.side != Order::Buy && m_order.side != Order::Sell)
		{
			throw std::exception("bad order side");
		}

		++i; m_order.quantity = ::atoi(i->c_str());

		++i; m_order.price = ::atof(i->c_str());
	}

	void CmdAddOrder::execute(OrderBook & ob)
	{
		ob.addOrder(m_order);
	}

	void CmdRemoveOrder::execute(OrderBook & ob)
	{
		ob.deleteOrder(m_order);
	}

	void CmdModifyOrder::execute(OrderBook & ob)
	{
		ob.modifyOrder(m_order);
	}

	void CmdTrade::execute(OrderBook & ob)
	{
		ob.trade(m_trade);
	}

	void CmdTrade::parse(const std::string & command)
	{
		typedef std::list<std::string> StringsList;

		StringsList sList = tokenize(command, ',');

		// trade command has following format - cmd,amount,price
		if (sList.size() != detail::cTradeCmdParametersCount)
		{
			throw std::exception("bad command");
		}

		StringsList::iterator i = sList.begin(), iEnd = sList.end();

		++i; m_trade.quantity = ::atoi(i->c_str());
		++i; m_trade.price = ::atof(i->c_str());
	}
}


